package org.example.aienglishapp_login.entity.login;

import com.fasterxml.jackson.annotation.JsonBackReference;
import jakarta.persistence.*;
import jakarta.validation.constraints.*;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;

import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;

/**
 * 用户实体类。
 * 该类用于存储用户的账号信息、登录信息等。
 *
 * @author xlj
 * @version 1.0
 * @since 2024-10-1
 */
@Getter
@Setter
@Entity
@EqualsAndHashCode(of = {"userId"})
@Table(name = "users", uniqueConstraints = {
        @UniqueConstraint(columnNames = "user_name")
})
public class User {

    /**
     * 用户的个人资料信息。
     * 使用一对一关系映射，并通过 {@code userProfile} 对象维护与用户的关系。
     */
    @OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
    @JsonBackReference
    private UserProfile userProfile;

    /**
     * 用户的唯一标识符。
     * 该字段是主键，并由数据库自动生成。
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long userId;

    /**
     * 用户名。
     * 该字段不能为空，最大长度为20个字符，并且在数据库中必须是唯一的。
     */
    @NotBlank
    @Size(max = 20)
    @Column(name = "user_name", nullable = false, unique = true)
    private String userName;

    /**
     * 用户的手机号码。
     * 手机号码为11位，并遵循中国手机号格式，且在数据库中必须是唯一的。
     */
    @Size(min = 11, max = 11)
    @Pattern(regexp = "^(1[3-9]\\d{9})$", message = "Invalid phone number.")
    @Column(unique = true)
    private String phone;

    /**
     * 用户密码。
     * 密码不能为空，最短为8个字符，并且必须包含至少一个小写字母、一个大写字母和一个数字。
     */
    @NotBlank
    @Size(min = 8)
    @Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$", message = "Password must contain at least one uppercase letter, one lowercase letter, and one digit.")
    @Column(name = "user_password", nullable = false)
    private String userPassword;

    /**
     * 用户状态。
     * 状态值范围为1到10，默认值为1。
     */
    @NotNull
    @Min(1)
    @Max(10)
    @Column(name = "user_status", nullable = false, columnDefinition = "number default 1")
    private Integer userStatus;

    /**
     * 用户注册时间。
     * 该字段记录用户注册的时间，不可更新。
     */
    @Column(name = "registration_time", updatable = false)
    private Timestamp registrationTime;

    /**
     * 用户最后登录时间。
     * 该字段记录用户最后一次登录的时间。
     */
    @Column(name = "last_login_time")
    private Timestamp lastLoginTime;

    /**
     * 用户最后修改时间。
     * 该字段记录用户信息最后一次被修改的时间。
     */
    @Column(name = "last_modified_time")
    private Timestamp lastModifiedTime;

    /**
     * 用户积分。
     * 积分值范围为0到999999，默认值为0。
     */
    @Column(name = "user_points", columnDefinition = "number default 0 check (user_points between 0 and 999999)")
    private Integer userPoints;

    /**
     * 用户经验值。
     * 经验值范围为0到999999，默认值为0。
     */
    @Column(name = "experience_points", columnDefinition = "number default 0 check (experience_points between 0 and 999999)")
    private Integer experiencePoints;

    /**
     * 设置用户的个人资料信息，并确保双向关联正确设置。
     *
     * @param userProfile 用户的个人资料信息
     */
    public void setUserProfile(UserProfile userProfile) {
        this.userProfile = userProfile;
        if (userProfile != null) {
            userProfile.setUser(this);
        }
    }

    /**
     * 用户的角色集合。
     * 使用多对多关系映射，并通过 "user_roles" 中间表来维护用户与角色之间的关系。
     */
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
            name = "user_roles",
            joinColumns = @JoinColumn(name = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "role_id")
    )
    private Set<Role> roles = new HashSet<>();

    @Override
    public String toString() {
        StringBuilder rolesString = new StringBuilder();
        if (roles != null) {
            for (Role role : roles) {
                if (role != null) {
                    rolesString.append(role.toString()).append(", ");
                }
            }
            if (!rolesString.isEmpty()) {
                rolesString.setLength(rolesString.length() - 2);
            }
        }

        String userProfileInfo = userProfile != null ? userProfile.toString() : "null";

        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", phone='" + phone + '\'' +
                ", userStatus=" + userStatus +
                ", registrationTime=" + registrationTime +
                ", lastLoginTime=" + lastLoginTime +
                ", lastModifiedTime=" + lastModifiedTime +
                ", userPoints=" + userPoints +
                ", experiencePoints=" + experiencePoints +
                ", roles=[" + rolesString + "]" +
                ", userProfile=" + userProfileInfo +
                '}';
    }
}